/**
 *    Copyright (C) 2008  Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */


#include <cubefs/api/api.hpp>
#include <iostream>
#include <bm_tools.h>

#include <vector>
#include <set>
#include <algorithm>

using namespace cubefs;
using namespace cubefs::api;
using namespace cubefs::core;

using namespace std;

const Int SIZE = 4000;

const BigInt MAX_VALUE = 0x7fffffffffffffff;

struct KVPair {
    BigInt	key_;
    IDValue	value_;
    
    KVPair(BigInt key, const IDValue &value): key_(key), value_(value) {}
    
    KVPair(){}
};

typedef vector<KVPair> PairVector;

bool KVPairSortPredicate(const KVPair& d1, const KVPair& d2)
{
  return d1.key_ < d2.key_;
}

void sort(PairVector& v) {
    std::sort(v.begin(), v.end(), KVPairSortPredicate);
}

void checkIterator(TreeMap* map, TreeMap::Pair* pair, PairVector& pairs) {
	TreeMapIterator* iter = (TreeMapIterator*) map->CreateIterator();

	StaticListOfTyped* keys = TypedCast<StaticListOfTyped>(pair->key());
        Number* key   = TypedCast<Number>(keys->Get(pair->GetIdx()));
	TypedIDValue* value = TypedCast<TypedIDValue>(pair->value());

	Int idx = 0;
	while (!iter->IsFlag(Iterator::ITER_EOF)) {
	    iter->GetValue(pair);
	    
	    if (pairs[idx].key_ != key->GetBigIntValue()) cout<<"key "<<idx<<endl;
	    
	    iter->Next();
	    idx++;
	}
	
	if (idx != pairs.size()) cout<<"size "<<idx<<" "<<pairs.size()<<endl;
}

set<long long> randoms;

long long getLongRandom() {
    long long rnd = 0;
    int cnt = 0;
    while (randoms.count(rnd = get_random(10000)) > 0) {
	cnt++;
	if (cnt == 10000) throw "can't create random value";
    }
    randoms.insert(rnd);
    return rnd;
}



int main(int argc, char **argv, const char** envp) {
	InitTypeSystem(envp);

	PairVector pairs;
	PairVector pairs_sorted;

	for (Int c = 0; c < SIZE; c++)
	{
		KVPair pair(getLongRandom(), IDValue());

		pairs.push_back(pair);
		pairs_sorted.push_back(pair);
	}

	sort(pairs_sorted);

	for (Int x = 0; x < 1000; x++)
	{
		Container* container = Container::Create("Stream", "0.0.0");
		container->GetManager()->GetLogger()->SetLogLevel(LogHandler::ERROR);

		cubefs::api::IdxMap* map = (cubefs::api::IdxMap*) container->CreateCollection(3, 1);
		map->SetMaxChildrenPerNode(5);

		TreeMap::Pair* pair   =  map->CreatePairHolder();

		StaticListOfTyped* keys = TypedCast<StaticListOfTyped>(pair->key());
		Number* key   = TypedCast<Number>(keys->Get(pair->GetIdx()));
		TypedIDValue* value = TypedCast<TypedIDValue>(pair->value());

		for (int c = 0; c < SIZE; c++)
		{
			key->SetBigIntValue(pairs[c].key_);
			map->Put(pair);
		}

		int from, to, cc = x;
		if (cc == 0) {
			from = 0;
			to = SIZE - 1;
		}
		else if (cc == 1) {
			from = 0;
			to = SIZE/2;
		}
		else if (cc == 2) {
			from = SIZE/2;
			to = SIZE - 1;
		}
		else {
			from = get_random(SIZE/2 - 1);
			to = SIZE/2 + get_random(SIZE/2);
		}

		PairVector result;
		for (int d = 0; d < pairs_sorted.size(); d++)
		{
			if (d < from || d > to) result.push_back(pairs_sorted[d]);
		}

		TreeMap::Pair*		from_pair = map->CreatePairHolder();
		StaticListOfTyped* 	from_keys = TypedCast<StaticListOfTyped>(from_pair->key());
		Number* 		from_key   = TypedCast<Number>(from_keys->Get(from_pair->GetIdx()));


		TreeMap::Pair*		to_pair = map->CreatePairHolder();
		StaticListOfTyped* 	to_keys = TypedCast<StaticListOfTyped>(to_pair->key());
		Number* 		to_key  = TypedCast<Number>(to_keys->Get(to_pair->GetIdx()));

		from_key->SetBigIntValue(pairs_sorted[from].key_);
		to_key->SetBigIntValue(pairs_sorted[to].key_ + 1);

		map->Remove(from_pair, to_pair);

		delete from_pair;
		delete to_pair;



		long size = SIZE - (to - from + 1);
		if (size != map->GetSize()) cout<<"Remove.size "<<x<<endl;
		container->Check();

		checkIterator(map, pair, result);

		delete container;
	}
}
